#include <iostream>
#include <string>
#include <cerrno>
#include <cassert>
#include <functional>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Socket.h"
#include "Epoll.hpp"

class epoll
{
    static const int gnum = 128;
    using func_t = std::function<void(std::string)>;

public:
    epoll(const uint16_t &port = 8080)
    {
        _listensock = Sock().Socket();
        Sock().Bind(_listensock, _port);
        Sock().Listen(_listensock);
        // 申请空间
        _revs = new struct epoll_event[_revs_num];

        _epfd = Epoll::EpollCreate();
        logMessage(DEBUG, "init success, listensock: %d, epfd: %d", _listensock, _epfd); // 3, 4
        // 3. 将listensock，先添加到epoll中，让epoll帮我们管理起来
        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
            exit(6);
        logMessage(DEBUG, "add listensock to epoll success."); // 3, 4
    }

    void LoopOnce(int timeout)
    {
        int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);
        switch (n)
        {
        case -1:
            logMessage(WARING, "WaitEpoll ERROR:%d %s", errno, strerror(errno));
            break;
        case 0:
            logMessage(DEBUG, "WaitEpoll timeout:%d %s", errno, strerror(errno));
            break;
        case 1:
            logMessage(DEBUG, "create right,get a events");
            HandlerEvents(n);
            break;
        }
    }

    void HandlerEvents(int n)
    {
        assert(n > 0);
        for (int i = 0; i < n; i++)
        {
            uint32_t revents = _revs[i].events;
            int sock = _revs[i].data.fd;
            if (revents & EPOLLIN)
            {
                if (sock == _listensock)
                    Accepter(_listensock); // 1. listensock 就绪
                else
                    Recver(sock);
            }
            else
            {
                logMessage(WARING, "TIME OUT");
            }
        }
    }
    void Accepter(int _listensock)
    {
        std::string clickip;
        uint16_t clickport;
        int sock = Sock().Accept(_listensock, &clickport, &clickip);
        if (sock >= 0)
        {
            if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN))
                return;
            logMessage(DEBUG, "add new sock : %d to epoll success", sock);
        }
        else
        {
            logMessage(WARING, "sock error");
        }
    }
    void Recver(int sock)
    {
        char buff[1024];
        ssize_t n = recv(sock, buff, sizeof(buff) - 1, 0);
        if (n < 0)
        {
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;
            // 2. 在close文件
            close(sock);
            logMessage(WARING, " recv error:%d.%s", errno, strerror(errno));
        }
        else if (n == 0)
        {
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;
            // 2. 在close文件
            close(sock);
            logMessage(NORMAL, "client %d quit, me too...", sock);
        }
        else
        {
            buff[n] = 0;
            _HandlerRequest(buff); // 2. 处理数据
        }
    }
    void Start()
    {
        int timeout = -1;
        while (true)
        {
            LoopOnce(timeout);
        }
    }

private:
    uint16_t _port;
    int _listensock;
    int _epfd;

    struct epoll_event *_revs;
    int _revs_num;
    func_t _HandlerRequest;
};
